/**
 * 通用工具函数
 * 提供项目中常用的通用工具函数
 */

/**
 * 防抖函数
 * @param func 要防抖的函数
 * @param delay 延迟时间（毫秒）
 * @returns 防抖后的函数
 */
export const debounce = <T extends (...args: any[]) => any>(
  func: T,
  delay: number
): ((...args: Parameters<T>) => void) => {
  let timeoutId: number;
  
  return (...args: Parameters<T>) => {
    clearTimeout(timeoutId);
    timeoutId = window.setTimeout(() => func(...args), delay);
  };
};

/**
 * 节流函数
 * @param func 要节流的函数
 * @param delay 延迟时间（毫秒）
 * @returns 节流后的函数
 */
export const throttle = <T extends (...args: any[]) => any>(
  func: T,
  delay: number
): ((...args: Parameters<T>) => void) => {
  let lastCall = 0;
  
  return (...args: Parameters<T>) => {
    const now = Date.now();
    if (now - lastCall >= delay) {
      lastCall = now;
      func(...args);
    }
  };
};

/**
 * 深拷贝对象
 * @param obj 要拷贝的对象
 * @returns 深拷贝后的对象
 */
export const deepClone = <T>(obj: T): T => {
  if (obj === null || typeof obj !== 'object') return obj;
  if (obj instanceof Date) return new Date(obj.getTime()) as unknown as T;
  if (obj instanceof Array) return obj.map(item => deepClone(item)) as unknown as T;
  if (typeof obj === 'object') {
    const clonedObj = {} as T;
    for (const key in obj) {
      if (obj.hasOwnProperty(key)) {
        clonedObj[key] = deepClone(obj[key]);
      }
    }
    return clonedObj;
  }
  return obj;
};

/**
 * 生成随机字符串
 * @param length 字符串长度
 * @param chars 可选字符集
 * @returns 随机字符串
 */
export const generateRandomString = (
  length: number = 8,
  chars: string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
): string => {
  let result = '';
  for (let i = 0; i < length; i++) {
    result += chars.charAt(Math.floor(Math.random() * chars.length));
  }
  return result;
};

/**
 * 生成UUID
 * @returns UUID字符串
 */
export const generateUUID = (): string => {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
    const r = Math.random() * 16 | 0;
    const v = c === 'x' ? r : (r & 0x3 | 0x8);
    return v.toString(16);
  });
};

/**
 * 获取URL参数
 * @param url 可选的URL，默认为当前页面URL
 * @returns 参数对象
 */
export const getUrlParams = (url?: string): Record<string, string> => {
  const urlStr = url || window.location.href;
  const params: Record<string, string> = {};
  const urlSearchParams = new URLSearchParams(urlStr.split('?')[1] || '');
  for (const [key, value] of urlSearchParams) {
    params[key] = value;
  }
  return params;
};

/**
 * 设置URL参数
 * @param params 参数对象
 * @param replace 是否替换当前历史记录
 */
export const setUrlParams = (params: Record<string, string>, replace: boolean = false): void => {
  const url = new URL(window.location.href);
  Object.entries(params).forEach(([key, value]) => {
    if (value) {
      url.searchParams.set(key, value);
    } else {
      url.searchParams.delete(key);
    }
  });
  
  if (replace) {
    window.history.replaceState({}, '', url.toString());
  } else {
    window.history.pushState({}, '', url.toString());
  }
};

/**
 * 下载文件
 * @param url 文件URL
 * @param filename 可选的文件名
 */
export const downloadFile = (url: string, filename?: string): void => {
  const link = document.createElement('a');
  link.href = url;
  if (filename) {
    link.download = filename;
  }
  link.target = '_blank';
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
};

/**
 * 下载Blob数据
 * @param blob Blob数据
 * @param filename 文件名
 */
export const downloadBlob = (blob: Blob, filename: string): void => {
  const url = URL.createObjectURL(blob);
  downloadFile(url, filename);
  URL.revokeObjectURL(url);
};

/**
 * 复制文本到剪贴板
 * @param text 要复制的文本
 * @returns 是否复制成功
 */
export const copyToClipboard = async (text: string): Promise<boolean> => {
  try {
    if (navigator.clipboard && window.isSecureContext) {
      await navigator.clipboard.writeText(text);
      return true;
    } else {
      // 降级方案
      const textArea = document.createElement('textarea');
      textArea.value = text;
      textArea.style.position = 'fixed';
      textArea.style.left = '-999999px';
      textArea.style.top = '-999999px';
      document.body.appendChild(textArea);
      textArea.focus();
      textArea.select();
      try {
        const result = document.execCommand('copy');
        return result;
      } finally {
        document.body.removeChild(textArea);
      }
    }
  } catch (error) {
    console.error('复制失败:', error);
    return false;
  }
};

/**
 * 获取文件扩展名
 * @param filename 文件名
 * @returns 文件扩展名
 */
export const getFileExtension = (filename: string): string => {
  return filename.slice((filename.lastIndexOf('.') - 1 >>> 0) + 2);
};

/**
 * 获取文件名（不含扩展名）
 * @param filename 完整文件名
 * @returns 不含扩展名的文件名
 */
export const getFileName = (filename: string): string => {
  return filename.substring(0, filename.lastIndexOf('.')) || filename;
};

/**
 * 检查是否为移动设备
 * @returns 是否为移动设备
 */
export const isMobile = (): boolean => {
  return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
    navigator.userAgent
  );
};

/**
 * 获取浏览器信息
 * @returns 浏览器名称和版本
 */
export const getBrowserInfo = (): { name: string; version: string } => {
  const userAgent = navigator.userAgent;
  let browserName = 'Unknown';
  let browserVersion = 'Unknown';
  
  if (userAgent.indexOf('Chrome') > -1) {
    browserName = 'Chrome';
    browserVersion = userAgent.match(/Chrome\/(\d+)/)?.[1] || 'Unknown';
  } else if (userAgent.indexOf('Firefox') > -1) {
    browserName = 'Firefox';
    browserVersion = userAgent.match(/Firefox\/(\d+)/)?.[1] || 'Unknown';
  } else if (userAgent.indexOf('Safari') > -1) {
    browserName = 'Safari';
    browserVersion = userAgent.match(/Version\/(\d+)/)?.[1] || 'Unknown';
  } else if (userAgent.indexOf('Edge') > -1) {
    browserName = 'Edge';
    browserVersion = userAgent.match(/Edge\/(\d+)/)?.[1] || 'Unknown';
  }
  
  return { name: browserName, version: browserVersion };
};

/**
 * 树形数据扁平化
 * @param tree 树形数据
 * @param childrenKey 子节点键名
 * @returns 扁平化数组
 */
export const flattenTree = <T extends Record<string, any>>(
  tree: T[],
  childrenKey: string = 'children'
): T[] => {
  const result: T[] = [];
  
  const traverse = (nodes: T[]) => {
    nodes.forEach(node => {
      result.push(node);
      if (node[childrenKey] && Array.isArray(node[childrenKey])) {
        traverse(node[childrenKey]);
      }
    });
  };
  
  traverse(tree);
  return result;
};

/**
 * 扁平数据转树形结构
 * @param array 扁平数据数组
 * @param idKey ID键名
 * @param parentIdKey 父ID键名
 * @param childrenKey 子节点键名
 * @param rootValue 根节点的父ID值
 * @returns 树形结构数组
 */
export const arrayToTree = <T extends Record<string, any>>(
  array: T[],
  idKey: string = 'id',
  parentIdKey: string = 'parentId',
  childrenKey: string = 'children',
  rootValue: any = null
): T[] => {
  const result: T[] = [];
  const map = new Map<any, T>();
  
  // 初始化map
  array.forEach(item => {
    map.set(item[idKey], { ...item, [childrenKey]: [] });
  });
  
  // 构建树形结构
  array.forEach(item => {
    const node = map.get(item[idKey])!;
    if (item[parentIdKey] === rootValue || !map.has(item[parentIdKey])) {
      result.push(node);
    } else {
      const parent = map.get(item[parentIdKey]);
      if (parent) {
        parent[childrenKey].push(node);
      }
    }
  });
  
  return result;
};

/**
 * 在树形结构中查找节点
 * @param tree 树形数据
 * @param predicate 查找条件函数
 * @param childrenKey 子节点键名
 * @returns 找到的节点或undefined
 */
export const findInTree = <T extends Record<string, any>>(
  tree: T[],
  predicate: (node: T) => boolean,
  childrenKey: string = 'children'
): T | undefined => {
  for (const node of tree) {
    if (predicate(node)) {
      return node;
    }
    if (node[childrenKey] && Array.isArray(node[childrenKey])) {
      const found = findInTree(node[childrenKey], predicate, childrenKey);
      if (found) {
        return found;
      }
    }
  }
  return undefined;
};

/**
 * 获取节点在树中的路径
 * @param tree 树形数据
 * @param targetId 目标节点ID
 * @param idKey ID键名
 * @param childrenKey 子节点键名
 * @returns 节点路径数组
 */
export const getTreePath = <T extends Record<string, any>>(
  tree: T[],
  targetId: any,
  idKey: string = 'id',
  childrenKey: string = 'children'
): T[] => {
  const findPath = (nodes: T[], path: T[] = []): T[] | null => {
    for (const node of nodes) {
      const currentPath = [...path, node];
      
      if (node[idKey] === targetId) {
        return currentPath;
      }
      
      if (node[childrenKey] && Array.isArray(node[childrenKey])) {
        const found = findPath(node[childrenKey], currentPath);
        if (found) {
          return found;
        }
      }
    }
    return null;
  };
  
  return findPath(tree) || [];
};

/**
 * 休眠函数
 * @param ms 休眠时间（毫秒）
 * @returns Promise
 */
export const sleep = (ms: number): Promise<void> => {
  return new Promise(resolve => setTimeout(resolve, ms));
};

/**
 * 重试函数
 * @param fn 要重试的函数
 * @param maxRetries 最大重试次数
 * @param delay 重试间隔（毫秒）
 * @returns Promise
 */
export const retry = async <T>(
  fn: () => Promise<T>,
  maxRetries: number = 3,
  delay: number = 1000
): Promise<T> => {
  let lastError: Error;
  
  for (let i = 0; i <= maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      lastError = error as Error;
      if (i < maxRetries) {
        await sleep(delay);
      }
    }
  }
  
  throw lastError!;
};

/**
 * 数组去重
 * @param array 数组
 * @param key 可选的对象键名，用于对象数组去重
 * @returns 去重后的数组
 */
export const unique = <T>(array: T[], key?: keyof T): T[] => {
  if (key) {
    const seen = new Set();
    return array.filter(item => {
      const value = item[key];
      if (seen.has(value)) {
        return false;
      }
      seen.add(value);
      return true;
    });
  }
  return [...new Set(array)];
};

/**
 * 数组分组
 * @param array 数组
 * @param key 分组键
 * @returns 分组后的对象
 */
export const groupBy = <T, K extends keyof T>(
  array: T[],
  key: K
): Record<string, T[]> => {
  return array.reduce((groups, item) => {
    const groupKey = String(item[key]);
    if (!groups[groupKey]) {
      groups[groupKey] = [];
    }
    groups[groupKey].push(item);
    return groups;
  }, {} as Record<string, T[]>);
};

/**
 * 数组分块
 * @param array 数组
 * @param size 每块大小
 * @returns 分块后的二维数组
 */
export const chunk = <T>(array: T[], size: number): T[][] => {
  const chunks: T[][] = [];
  for (let i = 0; i < array.length; i += size) {
    chunks.push(array.slice(i, i + size));
  }
  return chunks;
};

/**
 * 对象路径取值
 * @param obj 对象
 * @param path 路径（如 'a.b.c' 或 ['a', 'b', 'c']）
 * @param defaultValue 默认值
 * @returns 取到的值或默认值
 */
export const get = (obj: any, path: string | string[], defaultValue?: any): any => {
  const keys = Array.isArray(path) ? path : path.split('.');
  let result = obj;
  
  for (const key of keys) {
    if (result == null || typeof result !== 'object') {
      return defaultValue;
    }
    result = result[key];
  }
  
  return result !== undefined ? result : defaultValue;
};

/**
 * 对象路径设值
 * @param obj 对象
 * @param path 路径（如 'a.b.c' 或 ['a', 'b', 'c']）
 * @param value 要设置的值
 * @returns 修改后的对象
 */
export const set = (obj: any, path: string | string[], value: any): any => {
  const keys = Array.isArray(path) ? path : path.split('.');
  const lastKey = keys.pop()!;
  let current = obj;
  
  for (const key of keys) {
    if (!(key in current) || typeof current[key] !== 'object') {
      current[key] = {};
    }
    current = current[key];
  }
  
  current[lastKey] = value;
  return obj;
}; 